package com.marketlive.entity;

/*
 * (C) Copyright MarketLive. 2006. All rights reserved.
 * MarketLive is a trademark of MarketLive, Inc.
 * Warning: This computer program is protected by copyright law and international treaties.
 * Unauthorized reproduction or distribution of this program, or any portion of it, may result
 * in severe civil and criminal penalties, and will be prosecuted to the maximum extent
 * possible under the law.
 */

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.marketlive.entity.IAttributePage;
import java.io.Serializable;

/**
 * An abstract class representing a default implementation of IAttributePage interface.
 */
abstract public class AttributePage implements IAttributePage, Serializable {
    
    private static Log log = LogFactory.getLog(AttributePage.class);

   /**
    * {@inheritDoc}
    */     
    abstract public String getName();

   /**
     * Defines if this page contains values that need to be persisted. This basic implementation
     * checks for null property values as well as empty strings.
     * 
     * @return true if this page contains values that need to be persisted, false if all the properties
     * values in this page are either null or an empty string.
     */
    public boolean isEmpty() { 
        boolean isEmpty = true;
        Method method = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(this.getClass());
            MethodDescriptor[] methods = beanInfo.getMethodDescriptors();
      
            for (int i = 0; i < methods.length && isEmpty; i++) {
                MethodDescriptor methodDescriptor = (MethodDescriptor) methods[i];
                method = methodDescriptor.getMethod();
                String methodName = method.getName();
                Class returnType = method.getReturnType();

                // Only invoke getter methods named per the bean spec.
                // - getClass is always the 1st method and always has an object reference.
                // - getName will always return the name of the attribute Page - even if values are null
                if (isCallableMethod(methodName)) {
                    Object value = method.invoke(this, (Object[]) null);
                    if (returnType.isInstance(new String())){
                        isEmpty = (value == null || ((String)value).trim().equals(""));  
                    } else {
                        isEmpty = (value == null);
                    }
                }
            }
        } catch (IntrospectionException e) {
            log.error("Introspection exception occurred attempting to introspect bean:" + this + " method: " + method.getName());
        } catch (Exception e) {
            log.error("Reflection exception occurred attempting to introspect bean:" + this + " method: " + method.getName());
        }
        return isEmpty;
    }
    
    /**
     * Defines if a method with the specified name can be called by reflection.
     *
     * @param methodName 
     * @return true if the method can be called, false otherswise.
     */
    protected boolean isCallableMethod(String methodName){
        if ((methodName.startsWith("get") || methodName.startsWith("is")) &&
                (!methodName.equals("getClass")) &&
                (!methodName.equals("getName")) &&
                (!methodName.equals("isEmpty"))) {
            return true;
        }
        return false;
    }

    /**
    * {@inheritDoc}
    */
    public abstract IAttributePage clone() throws CloneNotSupportedException;

}
